package com.effectiv.crm.controller;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;
import javax.validation.Valid;

import jodd.util.ReflectUtil;
import jodd.util.StringUtil;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.BeanUtils;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.effectiv.crm.domain.FileUploadDetails;
import com.effectiv.crm.domain.Lead;
import com.effectiv.crm.service.api.ImportService;
import com.effectiv.crm.service.api.LeadService;
import com.effectiv.crm.service.api.PickListService;



@Slf4j
@Controller
@RequestMapping("/lead")
public class LeadController {
	
	@Inject
	private LeadService leadService;
	
	@Inject
	private ImportService importService;
	
	@Inject
	private PickListService pickListService;
	
	
	private String ignoreFields [] = {"serialVersionUID","assignedUser","assignedGroup","converted"};
	
	//TODO - fix synchronization issue here, move to post construct rather
	private List<String> leadFields;
	
	@RequestMapping("/importstart")
	public String beginImport(Model model){
		//TODO - move to an util class
		
		if(leadFields == null){
			Field fields [] = ReflectUtil.getAccessibleFields(Lead.class);
			leadFields = new ArrayList<String>();
			String fieldName = null;
			
			for(Field f : fields){
				fieldName = f.getName();
				if(StringUtil.equalsOne(fieldName,ignoreFields) == -1){
					leadFields.add(fieldName);
				}
			}
		}
		
		log.info("Lead fields = {}", leadFields);
		model.addAttribute("leadFields",leadFields);
		
		return "uploadleadfile";
	}
	
	@RequestMapping("/upload")
	public  String uploadFile(@RequestParam("file") MultipartFile file
			,@RequestParam("cols") String columns[],@RequestParam("delimiter") char delimiter, 
			@RequestParam(value="header",required=false,defaultValue="false") boolean header,Model m){
		
		
		FileUploadDetails fd = new FileUploadDetails();
		fd.setContentType(file.getContentType());
		fd.setName(file.getName());
		fd.setOriginalFileName(file.getOriginalFilename());
		fd.setSize(file.getSize());
		fd.setColumns(columns);
		fd.setDelimiter(delimiter);
		fd.setHeader(header);
		
		boolean inputStreamError = false;
		try {
			fd.setInputStream(file.getInputStream());
		} catch (IOException e) {
			inputStreamError = true;
			m.addAttribute("message-error",
					"Error opening file stream.");
		}
		
		if(!inputStreamError){
			
			try{
				importService.preProcess(fd, Lead.class);
				importService.process(fd, Lead.class);
				m.addAttribute("message","Lead file import submitted. Request Id # - ");
			}
			catch(Exception e){
				m.addAttribute("message-error",
						e.getMessage());
			}
		}
		
		
		m.addAttribute("leadFields",leadFields);
        return "uploadleadfile";
		
	
	}
	
	

	@RequestMapping("/list")
	public String list(Model model) {
		model.addAttribute(leadService.findByDeleted(false));
		return "listleads";
	}

	
	
	@RequestMapping(value={"/edit","/new","/details"})
	public String editOrNew(Model model,@RequestParam(value="id", required=false) String id
			,@RequestParam(value="view", required=false, defaultValue="false") boolean view
			) {
		Lead lead = null;
		
		boolean edit = false;
		boolean newLead = false;
		
		if(StringUtils.isEmpty(id)) {
			lead = BeanUtils.instantiate(Lead.class);
			newLead = true;
			
		}
		else{
			lead = leadService.findOne(id);
			
			//handle missing lead
			if(lead == null){
				//TODO - Return error and move back to list page
				lead = BeanUtils.instantiate(Lead.class);
				
			}
			
			
			if(!view){
				edit = true;
			}
		}
		

		model.addAttribute(lead);
		model.addAttribute("industries", pickListService.findByDomain("Industry"));
		model.addAttribute("statusList", pickListService.findByDomain("LeadStatus"));
		model.addAttribute("sourceList", pickListService.findByDomain("LeadSource"));
		model.addAttribute("ratingList", pickListService.findByDomain("LeadRating"));
		model.addAttribute("salutationList", pickListService.findByDomain("Salutation"));
		model.addAttribute("view", view);
		model.addAttribute("edit", edit);
		model.addAttribute("newLead", newLead);
		model.addAttribute("id", id);
		
		return "newlead";
	}
	
	@RequestMapping("/copy")
	public String copy(Model model,@RequestParam(value="id") String id) {
		Lead lead = leadService.findOne(id);
		if(lead != null )
			lead.setId(null);

		model.addAttribute(lead);
		model.addAttribute("industries", pickListService.findByDomain("Industry"));
		model.addAttribute("statusList", pickListService.findByDomain("LeadStatus"));
		model.addAttribute("sourceList", pickListService.findByDomain("LeadSource"));
		model.addAttribute("ratingList", pickListService.findByDomain("LeadRating"));
		model.addAttribute("salutationList", pickListService.findByDomain("Salutation"));
		model.addAttribute("view", false);
		model.addAttribute("edit", false);
		model.addAttribute("newLead", true);
		model.addAttribute("id", null);
		
		return "newlead";
	}
	
	
	@RequestMapping(value = "/update", method = RequestMethod.POST)
	public String update(@Valid Lead lead,
			BindingResult result, Model model) {
		
		log.info("Lead submitted for saving - {}", lead);
		
		if (result.hasErrors()) {
			return "newlead";
		}
		else{
			leadService.update(lead);
			model.addAttribute("message",
					"Lead updated successfully.");
		}
		
		
		model.addAttribute(lead);
		model.addAttribute("industries", pickListService.findByDomain("Industry"));
		model.addAttribute("statusList", pickListService.findByDomain("LeadStatus"));
		model.addAttribute("sourceList", pickListService.findByDomain("LeadSource"));
		model.addAttribute("ratingList", pickListService.findByDomain("LeadRating"));
		model.addAttribute("salutationList", pickListService.findByDomain("Salutation"));
		model.addAttribute("view", false);
		model.addAttribute("edit", true);
		model.addAttribute("newLead", false);
		model.addAttribute("id", lead.getId());
		
		return "newlead";
	}
	
	@RequestMapping(value = "/delete", method = RequestMethod.GET)
	public String delete(@RequestParam("id") String id,
			final RedirectAttributes redirectAttributes){
		Lead lead = new Lead();
		lead.setId(id);
		
		leadService.delete(lead);
		
		redirectAttributes.addFlashAttribute("message", "Lead deleted successfully.");
		
		return "redirect:list";
	}
	
	@RequestMapping(value = "/save", method = RequestMethod.POST)
	public String save(@Valid Lead lead,
			BindingResult result, Model model) {
		
		
		if (result.hasErrors()) {
			log.info("Result - {}",result);
			return "newlead";
		}
		else{
			
			log.info("Saving lead");
			lead.setId(null);
			leadService.save(lead);
			model.addAttribute("message",
					"Lead saved successfully.");
		}

		
		model.addAttribute(lead);
		model.addAttribute("industries", pickListService.findByDomain("Industry"));
		model.addAttribute("statusList", pickListService.findByDomain("LeadStatus"));
		model.addAttribute("sourceList", pickListService.findByDomain("LeadSource"));
		model.addAttribute("ratingList", pickListService.findByDomain("LeadRating"));
		model.addAttribute("salutationList", pickListService.findByDomain("Salutation"));
		model.addAttribute("view", true);
		model.addAttribute("edit", false);
		model.addAttribute("newLead", false);
		model.addAttribute("id", lead.getId());
		
		
		return "newlead";
	}
}
